import javax.microedition.lcdui.*;
import java.io.*;

//#if (Nokia && !MIDP2) || (Siemens && SX1)
    import com.nokia.mid.ui.*;
//#endif

//#if SOUND_NOKIA_RT
    import com.nokia.mid.sound.*;
//#elif SOUND_MMAPI
    import javax.microedition.media.*;
    import javax.microedition.media.control.*;
//#elif SAMSUNG_MMF
    import com.samsung.util.*;
//#elif SHARP_MMF
    import com.vodafone.v10.sound.*;
//#endif


public class MTMCanvas 
    //#if (Nokia && !MIDP2) || (Siemens && SX1)
        extends FullCanvas
    //#else
        extends Canvas 
    //#endif
    implements Runnable, Constants
    //#if SOUND_NOKIA_RT
        , SoundListener
    //#elif SOUND_MMAPI
        , PlayerListener
    //#endif
    //#if !FULL_CANVAS
        , CommandListener
    //#endif
{
    private final MTMMidlet midlet;

    //display
    public static int height;
    public static int width;

    //Game states
    public static byte nCurrentGameState;
    public static byte bCurrentTick;

    public volatile Thread mainThread;

    private static boolean  canvasLocked;

    private Image imgLogo;

    private long timeCurrent, timeSchduledTask;
    
    // coordinates of previous setClip
    static int setClipX1;
    static int setClipY1;
    static int setClipX2;
    static int setClipY2;

    //#if BACK_BUFFER_FULL
        private Image iDoubleBuffer = null;
        private Graphics gDoubleBuffer = null;
    //#endif

    //#if Nokia && E61
        public static int keyCode;
    //#endif
    public static int keysPressed;         // Keys were pressed
    public static int keysHold;            // Keys are held
    public static int keysReleased;        // Keys were released

    private boolean endOfGame;

    //#if SOUND_NOKIA_RT
        private static Sound[] sounds;
        private static byte soundState;
        public static byte soundId;

        private final static byte SS_STOPED  = 0;
        private final static byte SS_PLAYING = 1;
        private final static byte SS_PAUSED  = 2;
    //#elif SOUND_MMAPI
        private static Player[] soundPlayer;
        public static byte soundId;

        //#if USE_SOUND_VOLUME_CONTROL
            public static VolumeControl[] volumeControl;
            public static byte volumeLevel;
        //#endif

        private static final byte SS_NOT_LOADED = 0;
        private static final byte SS_PREFETCHED = 1;
        private static final byte SS_STARTED    = 2;
        private static final byte SS_CLOSED     = 3;
        private static final byte SS_REALIZED   = 4;
        private static final byte SS_UNREALIZED = 5;
      
        private static final int DURATION_ONCE = 1;
        private static final int DURATION_LOOP = -1;
    //#elif SAMSUNG_MMF
        private static AudioClip[] soundPlayer;
        private static byte soundId;
    //#elif SHARP_MMF
        public static SoundPlayer soundPlayer;
        private static Sound[] soundData;
        private static SoundTrack[] soundTracks;
    //#endif

    /**
     *
     */
    public MTMCanvas(MTMMidlet midlet) {
        this.midlet = midlet;
        //#if MIDP2
            setFullScreenMode(true);
        //#endif
        canvasLocked = false;

        //#if !FULL_CANVAS
            setCommandListener(this);
        //#endif

        //#if SOUND_NOKIA_RT
            sounds = new Sound[SOUND_COUNT];
        //#elif SOUND_MMAPI
            soundPlayer = new Player[SOUND_COUNT];
            //#if USE_SOUND_VOLUME_CONTROL
                volumeControl = new VolumeControl[SOUND_COUNT];
            //#endif
        //#elif SAMSUNG_MMF
            soundPlayer = new AudioClip[SOUND_COUNT];
        //#elif SHARP_MMF
            try{
                soundPlayer = SoundPlayer.getPlayer();
            } 
            catch (Exception e) {
                //e.printStackTrace();
            }
            soundData = new Sound[SOUND_COUNT];
            soundTracks = new SoundTrack[SOUND_COUNT];
        //#endif

        //#if BACK_BUFFER_FULL
            iDoubleBuffer = Image.createImage(DISPLAY_WIDTH, DISPLAY_HEIGHT);
            gDoubleBuffer = iDoubleBuffer.getGraphics();
        //#endif
    }

    /**
     *
     */

    void start() {
        if (midlet != null) {
            Display.getDisplay(midlet).setCurrent(this);
            if (mainThread == null) {
                mainThread = new Thread(this);
                mainThread.start();
            }
        }
    }

    /**
     *
     */
    void stop() {
        mainThread = null;
        //#if SOUND_MMAPI || SOUND_NOKIA_RT || SAMSUNG_MMF || SHARP_MMF
            soundUnload();
        //#endif
    }

    /**
     *
     */
    protected void hideNotify() {
        if ( nCurrentGameState == GAME_STATE_START ) {
            nCurrentGameState = GAME_STATE_IN_GAME_MENU;
            GameMenu.blReady = false;
        }
    }

    /**
     *
     */
    protected void showNotify() {
        if ( nCurrentGameState == GAME_STATE_IN_GAME_MENU ) {
            resetKeys();
            GameMenu.Init(this);
        }
    }

    /**
     *
     */
    public void run() {
        Thread currentThread = Thread.currentThread();
        try {
            endOfGame = false;

            width = DISPLAY_WIDTH;
            height = DISPLAY_HEIGHT;

            // coordinates of previous setClip
            setClipX1 = 0;
            setClipY1 = 0;
            setClipX2 = width;
            setClipY2 = height;

            imgLogo = Resources.LoadImage("/res/logo");

            long l_logo_start = System.currentTimeMillis();
            nCurrentGameState = GAME_STATE_LOGO;
            doRepaint();

            // load resources
            Resources.initCommonResources();
            Resources.initMenuResources();
            //#if !IMGGROUP_12x12xLimited
                Resources.initGameResources();
            //#endif

            //#if SOUND_NOKIA_RT
                soundLoad(SOUND_BONUS      , DATA_SOUND_BONUS);
                soundLoad(SOUND_DIE        , DATA_SOUND_DIE);
                soundLoad(SOUND_KILL       , DATA_SOUND_KILL);
                soundLoad(SOUND_LVL_CLEAR  , DATA_SOUND_LVL_CLEAR);
                soundLoad(SOUND_NEW_LIFE   , DATA_SOUND_NEW_LIFE);
                soundLoad(SOUND_THEME      , DATA_SOUND_THEME);
                soundLoad(SOUND_TIMEWARNING, DATA_SOUND_TIMEWARNING);
                soundState = SS_STOPED;
                soundId = -1;
            //#elif SOUND_MMAPI || SAMSUNG_MMF || SHARP_MMF
                soundLoad(SOUND_BONUS);
                soundLoad(SOUND_DIE);
                soundLoad(SOUND_KILL);
                soundLoad(SOUND_LVL_CLEAR);
                soundLoad(SOUND_NEW_LIFE);
                soundLoad(SOUND_THEME);
                soundLoad(SOUND_TIMEWARNING);
                soundId = -1;
            //#endif

         
            // logo end
            logoWait(l_logo_start, 2000);

            imgLogo = null;
            System.gc();

            Resources.loadSettings();
            //#if USE_SOUND_VOLUME_CONTROL
                if (volumeLevel == -1) {
                    volumeLevel = 20;
                    Resources.saveSettings();
                }

                for (int i = 0; i < volumeControl.length; i++) {
                    volumeControl[i].setLevel(volumeLevel);
                }
            //#endif

            // enter name
            if (GameMenu.editorLength == 0) {
                nCurrentGameState = GAME_STATE_EDIT_NAME;
            }
            else {
                //#if SOUND_NOKIA_RT || SOUND_MMAPI || SAMSUNG_MMF || SHARP_MMF
                    nCurrentGameState = GAME_STATE_ENABLE_SOUND;
                //#else
                    nCurrentGameState = GAME_STATE_SPLASH;
                //#endif
            }
            GameMenu.Init(this);

            bCurrentTick = 0;
            timeSchduledTask = System.currentTimeMillis();

            while ((currentThread == mainThread) && (nCurrentGameState != GAME_STATE_EXIT)) {
                // Only animate when the canvas is visible.
                timeCurrent = System.currentTimeMillis();
                //#if !IMGGROUP_12x12xLimited
                while (timeSchduledTask <= timeCurrent) {
                //#endif
                    tick(++bCurrentTick);

                    keysPressed = 0;
                    keysReleased = 0;

                //#if !IMGGROUP_12x12xLimited
                    timeSchduledTask += MILLIS_PER_TICK;
                }
                //#endif
                doRepaint();

                //#if IMGGROUP_12x12xLimited
                    while ((System.currentTimeMillis() - timeCurrent) < MILLIS_PER_TICK);
                //#endif
                try {
                    currentThread.sleep(10);
                }
                catch(Exception iex) {}
                currentThread.yield();
            }
            midlet.exitRequested();
        }
        catch(Exception e ) {
        }
    }

    /**
     *
     */
    public final void paint(Graphics g) {
        if (canvasLocked) return;
        canvasLocked = true;

        if (nCurrentGameState == GAME_STATE_START) {
            //#if BACK_BUFFER_FULL
                GameWorld.Draw(gDoubleBuffer);
                g.drawImage(iDoubleBuffer, 0, 0, Graphics.TOP|Graphics.LEFT);
            //#else
                GameWorld.Draw(g);
            //#endif
        }
        else if (nCurrentGameState == GAME_STATE_GET_READY) {
            GameWorld.Draw(g);

            int hw = width >> 1;
            int hh = height >> 1;
               
            Resources.DrawString(g, GameWorld.levelName, hw, hh - 5, Graphics.BOTTOM|Graphics.HCENTER, Resources.nOptFlg_BoldFnt);
            Resources.DrawString(g, StringsID.nStrID_GetReady, hw, hh + 5, Graphics.TOP|Graphics.HCENTER, Resources.nOptFlg_BoldFnt);
        }
        else if (nCurrentGameState == GAME_STATE_LOGO) {
            fillRect(g, 0, 0, width, height, 0xFFFFFF);
            if (imgLogo != null) {
                g.drawImage(imgLogo, width >> 1, height >> 1, Graphics.VCENTER | Graphics.HCENTER);
            }
        }
        else {
            //#if BACK_BUFFER_FULL
                GameMenu.Draw(gDoubleBuffer);
                g.drawImage(iDoubleBuffer, 0, 0, Graphics.TOP|Graphics.LEFT);
            //#else
                GameMenu.Draw(g);
            //#endif
        }
        canvasLocked = false;
    }

    /**
     *
     */
    public void doRepaint() {
        repaint();
        serviceRepaints();
    }

    /**
     *
     */
    public static boolean setClip(Graphics g, int x, int y, int w, int h, boolean maySkip) {
        // maySkip is true if it is not necessary to setClip - like for fillRect etc
        // false - for tiled images which need setClip anyway

        // range check values to fit the screen
        if (x >= width || y >= height) return false;

        if (w == 0) w = width;
        if (h == 0) h = height;

        if (x < 0) {
            w += x;
            if (w <= 0) return false;
            x = 0;
        }
        if (y < 0) {
            h += y;
            if (h <= 0) return false;
            y = 0;
        }

        if (x + w > width) w = width - x;
        if (y + h > height) h = height - y;

        if (x >= setClipX1 && x + w <= setClipX2 && y >= setClipY1 && y + h <= setClipY2 && maySkip) {
        }
        else {
            g.setClip(x, y, w, h);
            setClipX1 = x;
            setClipY1 = y;
            setClipX2 = x + w;
            setClipY2 = y + h;
        }
        return true;
    }

    /**
     *
     */
    public static void fillRect(Graphics g, int x, int y, int w, int h, int color) {
        if (setClip(g, x, y, w, h, true)) {
            g.setColor(color);
            g.fillRect(x, y, w, h);
        }
    }

    /**
     *
     */
    public static void drawRect(Graphics g, int x, int y, int w, int h, int color) {
        if (setClip(g, x, y, w, h, true)) {
            g.setColor(color);
            g.drawRect(x, y, w, h);
        }
    }

    /**
     *
     */
    private boolean loadLevel(int n_lev) {
        int i, j, iCount, jCount, tInt;
        byte rClassID;
        short rX, rY, tX, tY;
        DataInputStream dis = null;
        int[] path;
      
        GameWorld.rnd.setSeed( bCurrentTick );
        bCurrentTick = 0;
        GameWorld.nCompleteTicks = 0;

        try {
            GameWorld.levelName = Resources.GetString(StringsID.nStrID_Level) + " " + (n_lev+1);

            //#if !IMGGROUP_12x12xLimited
                dis = new DataInputStream(MTMMidlet.the_class.getResourceAsStream("/res/levels.m2l"));
            //#else
                dis = new DataInputStream(MTMMidlet.the_class.getResourceAsStream("/res/lvl" + n_lev + ".m2l"));
                n_lev = 0;
            //#endif

            if (dis != null) {
                //#if !FULL_CANVAS
                    removeAllCmds();
                //#endif

                int bytes = 4;
            
                //#if !IMGGROUP_12x12xLimited
                    GameWorld.n_levels = dis.readInt();
                //#else
                    GameWorld.n_levels = LEVELS_AMOUNT;
                    dis.skipBytes( 4 );
                //#endif

                if ((n_lev < 0) || (n_lev >= GameWorld.n_levels)) {
                    dis.close();
                    return false;
                }

                // level index
                int n_offset = 0;
                for (i = 0; i <= n_lev; i++) {
                    n_offset = dis.readInt();
                    bytes += 4;
                }

                // skip bytes
                int n_to_skip = n_offset - bytes;
                dis.skipBytes( n_to_skip );

                GameWorld.nInitalLevelTicks = GameWorld.nLevelTicks = dis.readShort();

                // starting point
                GameWorld.nStartX = dis.readShort();
                GameWorld.nStartY = dis.readShort();

                // matrix dim
                iCount = dis.readByte();
                jCount = dis.readByte();

                // game play screen size
                GameWorld.gps_width = iCount * TileDrawer.nTileWidth;
                GameWorld.gps_height = jCount * TileDrawer.nTileWidth;

                // tile matrix
                GameWorld.bTilesMatrix = new byte[iCount][jCount];

                GameWorld.m_nRepaintedBlocks = 0;
                GameWorld.m_nTotalBlocks = 0;
                for (i = 0; i < iCount; i++) {
                    for (j = 0; j < jCount; j++) {
                        byte b_tile_id = dis.readByte();
                        GameWorld.bTilesMatrix[i][j] = b_tile_id;

                        if ((b_tile_id < TilesID.nTileID_TilesCount) &&
                        //#if !IMGGROUP_12x12xLimited
                            (b_tile_id > TilesID.nTileID_bgs11) &&
                        //#else
                            (b_tile_id > TilesID.nTileID_bg5) &&
                        //#endif
                            (b_tile_id & 1) == 0) {
                            GameWorld.m_nTotalBlocks++;
                        }
                    }
                }

                doRepaint();

                iCount = dis.readByte();

                //#if !IMGGROUP_12x12xLimited
                    if (iCount > 0) {
                        GameWorld.decorObjects = new LevObj[iCount];
                        for (i = 0; i < iCount; i++) {
                            GameWorld.decorObjects[i] = new LevObj();
                            rClassID = dis.readByte();
                            rX = dis.readShort();
                            rY = dis.readShort();
                            //#if USE_GAME_TIPS
                                GameWorld.decorObjects[i].Init(i, ObjID.nObjID_DynCount + rClassID, rX, rY, null, this);
                            //#else
                                GameWorld.decorObjects[i].Init(i, ObjID.nObjID_DynCount + rClassID, rX, rY, null);
                            //#endif
                        }
                    }
                //#endif

                doRepaint();

                iCount = dis.readByte();
                if (iCount > 0) {
                    GameWorld.dynamicObjects = new LevObj[iCount];
                    for (i = 0; i < iCount; i++) {
                        rClassID = dis.readByte();
                        rX = dis.readShort();
                        rY = dis.readShort();
                        GameWorld.dynamicObjects[i] = new LevObj();
                        //#if USE_GAME_TIPS
                            GameWorld.dynamicObjects[i].Init(i, rClassID, rX, rY, dis, this);
                        //#else
                            GameWorld.dynamicObjects[i].Init(i, rClassID, rX, rY, dis);
                        //#endif
                    }
                }

                doRepaint();

                iCount = dis.readByte();
                if (iCount > 0) {
                    GameWorld.monsters = new Monster[iCount];
                    for (i = 0; i < iCount; i++) {
                        rClassID = dis.readByte();
                        rX = dis.readShort();
                        rY = dis.readShort();
                        switch (rClassID) {
                            case ObjID.nObjID_MonsterDragon:
                                jCount = dis.readByte();
                                path = new int[jCount];
                                for (j = 0; j < path.length; j++) {
                                    tX = dis.readShort();
                                    tY = dis.readShort();
                                    path[j] = ((tX << 16) & 0xFFFF0000) | (tY & 0x0000FFFF);
                                }
                                GameWorld.monsters[i] = new MortalFly(rX, rY, path);
                                path = null;
                                System.gc();
                            break;

                            case ObjID.nObjID_MonsterBeast:
                                tInt = GameWorld.getPlatfomEdges(rX, rY, Constants.PLATFORM_UP);
                                if (tInt != -1) {
                                    tX = (short)((tInt >> 16) & 0x0000ffff);
                                    tY = (short)(tInt & 0x0000ffff);
                                }
                                else {
                                    tX = rX;
                                    tY = rX;
                                }
                                GameWorld.monsters[i] = new JumpingBeast(rX, rY, tX, tY);
                            break;

                            case ObjID.nObjID_MonsterDrop:
                                tInt = GameWorld.getPlatfomEdges(rX, rY, Constants.PLATFORM_DOWN);
                                if (tInt != -1) {
                                    tX = (short)((tInt >> 16) & 0x0000ffff);
                                    tY = (short)(tInt & 0x0000ffff);
                                }
                                else {
                                    tX = rX;
                                    tY = rX;
                                }
                                GameWorld.monsters[i] = new Slime(rX, rY, tX, tY);
                            break;
                        }
                    }
                }

                doRepaint();
            
                GameWorld.nWndCX = GameWorld.nStartX;
                GameWorld.nWndCY = GameWorld.nStartY;

                Hero.Init();
                //#if BACK_BUFFER_FULL || BACK_BUFFER_LEVEL
                    GameWorld.prepareBackBuffer();
                //#endif
            
                //#if !FULL_CANVAS
                    addCmd(StringsID.nStrID_Pause, -1);
                //#endif

                return true;
            }
        }
        catch(Exception ex) {
            //System.out.println( ex.toString() );
        }
        finally {
            try {
                if (dis != null) {
                    dis.close();
                }
            }
            catch(Exception ex) {};
            dis = null;
            System.gc();
        }
        return false;
    }

    /**
     *
     */
    private void tick( byte b_tick ) {
        switch (nCurrentGameState) {
            case GAME_STATE_SPLASH: {
                if (GameMenu.tick()) {
                    GameMenu.CleanUp();
                    nCurrentGameState = GAME_STATE_MENU;
                    GameMenu.Init(this);
                }
                break;
            }

            case GAME_STATE_GET_READY: {
                //#if !IMGGROUP_12x12xLimited
                    if (GameWorld.decorObjects != null) {
                        for (int i = 0; i < GameWorld.decorObjects.length; i++) {
                            GameWorld.decorObjects[i].Tick(b_tick);
                        }
                    }
                //#endif

                if (bCurrentTick == 20) {
                    //#if USE_GAME_TIPS
                        if ((GameMenu.isGameTipsOn()) && (Hero.m_nLevel <= GameWorld.gameTips[Constants.TIP_LEVEL])) {
                            GameWorld.gameTips[Constants.TIP_LEVEL] = -1;

                            resetKeys();
                            GameMenu.strToText(StringsID.nStrID_TipLevel, true);
                            nCurrentGameState = GAME_STATE_SHOW_TIP;
                            GameMenu.Init(this);
                        }
                        else {
                            nCurrentGameState = GAME_STATE_START;
                        }
                    //#else
                        nCurrentGameState = GAME_STATE_START;
                    //#endif
                }
                break;
            }

            case GAME_STATE_START: {
                DoKey();
                int ret = GameWorld.Tick(b_tick);

                if ((ret == Hero.c_nRetHeroDeath) || (ret == GameWorld.GWRET_TIME_OVER) ) {
                    resetKeys();

                    if (Hero.m_nLives >= 0) {
                  
                        GameWorld.nLevelTicks = GameWorld.nInitalLevelTicks;

                        // reset to "true" pickaxes and dynamites
                        if (GameWorld.dynamicObjects != null) {
                            for (int i = 0; i < GameWorld.dynamicObjects.length; i++) {
                                if (GameWorld.dynamicObjects[i].nClassID == ObjID.nObjID_Bonus) {
                                    if ((GameWorld.dynamicObjects[i].m_nParam == LevObj.c_shBonusPickAxe) || (GameWorld.dynamicObjects[i].m_nParam == LevObj.c_shBonusDynamite)) {
                                        GameWorld.dynamicObjects[i].m_blActive = true;
                                    }
                                }
                            }
                        }

                        Hero.Init();
                        GameWorld.nWndCX = Hero.m_nPosX;
                        GameWorld.nWndCY = Hero.m_nPosY;

                        //#if BACK_BUFFER_FULL || BACK_BUFFER_LEVEL
                            GameWorld.prepareBackBuffer();
                        //#endif

                        bCurrentTick = 0;
                        nCurrentGameState = GAME_STATE_GET_READY;
                    }
                    else {
                        GameWorld.CleanUp();
                        //#if IMGGROUP_12x12xLimited
                            Resources.cleanGameResources();
                            Resources.initMenuResources();
                        //#endif

                        if (Hero.m_nTotalScores > 0) {
                            nCurrentGameState = GAME_STATE_UPLOAD_SCORE;
                            //#if !SCORE_SAVE_RMS
                                GameMenu.Init(this);
                            //#endif
                        }
                        else {
                            nCurrentGameState = GAME_STATE_MENU;
                            GameMenu.Init(this);
                        }
                    }
                }

                if ( ret == GameWorld.GWRET_COMPLETE ) {
                    resetKeys();
                    GameWorld.CleanUp();
                    Hero.m_nLevel++;
                    if (Hero.m_nLevel >= GameWorld.n_levels) {
                        //#if IMGGROUP_12x12xLimited
                            Resources.cleanGameResources();
                            Resources.initMenuResources();
                        //#endif
                        nCurrentGameState = GAME_STATE_FINAL_SCENE;
                        GameMenu.Init(this);
                    }
                    else {
                        if ((Hero.m_nLevel - 1) == Hero.m_nLevelMax) {
                            Hero.m_nLevelMax++;
                            Resources.saveSettings();
                        }

                        nCurrentGameState = GAME_STATE_LOADING;
                        GameMenu.Init(this);
                        doRepaint();

                        //#if BACK_BUFFER_FULL || BACK_BUFFER_LEVEL
                            GameWorld.clearBackBuffer();
                        //#endif

                        if ( loadLevel(Hero.m_nLevel) ) {
                            bCurrentTick = 0;
                            nCurrentGameState = GAME_STATE_GET_READY;
                        }
                    }
                }
                if (keyWasPressed(keyLEFTSOFT)) {
                    resetKeys();
                    //#if SOUND_NOKIA_RT || SOUND_MMAPI || SAMSUNG_MMF || SHARP_MMF
                        soundStop(soundId);
                    //#endif

                    nCurrentGameState = GAME_STATE_IN_GAME_MENU;
                    GameMenu.Init(this);
                }
                break;
            }

            case GAME_STATE_EDIT_NAME: {
                int n_cmd = GameMenu.ProcessKeys();
                if (n_cmd == StringsID.nStrID_Ok) {
                    resetKeys();
                    GameMenu.CleanUp();
                    //#if SOUND_NOKIA_RT || SOUND_MMAPI || SAMSUNG_MMF || SHARP_MMF
                        nCurrentGameState = GAME_STATE_ENABLE_SOUND;
                    //#else
                        nCurrentGameState = GAME_STATE_SPLASH;
                    //#endif
                    GameMenu.Init(this);
                }
                break;
            }
            //#if SOUND_NOKIA_RT || SOUND_MMAPI || SAMSUNG_MMF || SHARP_MMF
                case GAME_STATE_ENABLE_SOUND: {
                    int n_cmd = GameMenu.ProcessKeys();
                    if ((n_cmd == StringsID.nStrID_Yes) || (n_cmd == StringsID.nStrID_No)) {
                        resetKeys();
                        GameMenu.CleanUp();
                        nCurrentGameState = GAME_STATE_SPLASH;
                        GameMenu.Init(this);

                        if (n_cmd == StringsID.nStrID_Yes) {
                            GameMenu.enableSound(true);
                            soundPlay(SOUND_THEME);
                        }
                        else {
                            GameMenu.enableSound(false);
                        }
                    }
                    break;
                }
            //#endif

            case GAME_STATE_FINAL_SCENE: {
                if (GameMenu.ProcessKeys() == StringsID.nStrID_Ok) {
                    resetKeys();
                    GameMenu.CleanUp();
                    if (Hero.m_nTotalScores > 0) {
                        nCurrentGameState = GAME_STATE_UPLOAD_SCORE;
                        //#if !SCORE_SAVE_RMS
                            GameMenu.Init(this);
                        //#endif
                    }
                    else {
                        nCurrentGameState = GAME_STATE_MENU;
                        GameMenu.Init(this);
                    }
                }
                break;
            }

            case GAME_STATE_UPLOAD_SCORE: {
                boolean flag = false;
                //#if SCORE_SAVE_RMS
                    Resources.uploadScore(Hero.m_nTotalScores);
                    if (endOfGame) {
                        nCurrentGameState = GAME_STATE_EXIT;
                    }
                    else {
                        resetKeys();
                        GameMenu.CleanUp();
                        nCurrentGameState = GAME_STATE_MENU;
                        GameMenu.Init(this);
                    }
                //#else
                    int n_cmd = GameMenu.ProcessKeys();
                    if (n_cmd == StringsID.nStrID_Yes) {
                        flag = Resources.uploadScore(Hero.m_nTotalScores);
                        if (!flag) {
                            GameMenu.strToText(StringsID.nStrID_ConnectionLost, true);
                        }
                    }
                    else if (n_cmd == StringsID.nStrID_No) {
                        flag = true;
                    }
                    if (flag) {
                        if (endOfGame) {
                            nCurrentGameState = GAME_STATE_EXIT;
                        }
                        else {
                            resetKeys();
                            GameMenu.CleanUp();
                            nCurrentGameState = GAME_STATE_MENU;
                            GameMenu.Init(this);
                        }
                    }
                //#endif
                break;
            }

            //#if USE_GAME_TIPS
                case GAME_STATE_SHOW_TIP: {
                    //#if !IMGGROUP_12x12xLimited
                        if (GameWorld.decorObjects != null) {
                            for (int i = 0; i < GameWorld.decorObjects.length; i++) {
                                GameWorld.decorObjects[i].Tick(b_tick);
                            }
                        }
                    //#endif

                    if (GameMenu.ProcessKeys() == StringsID.nStrID_Ok) {
                        resetKeys();
                        GameMenu.CleanUp();
                        nCurrentGameState = GAME_STATE_START;
                        //#if !FULL_CANVAS
                            removeAllCmds();
                            addCmd(StringsID.nStrID_Pause, -1);
                        //#endif
                    }
                    break;
                }
            //#endif

            case GAME_STATE_MENU:
            case GAME_STATE_IN_GAME_MENU: {
                int n_cmd = GameMenu.ProcessKeys();
                resetKeys();
                switch ( n_cmd ) {
                    case StringsID.nStrID_SelectLevel: {
                        Hero.m_nLevel = GameMenu.nSelLine;
                    }

                    case StringsID.nStrID_NewGame: {
                        if (n_cmd != StringsID.nStrID_SelectLevel) {
                            Hero.m_nLevel = 0;
                        }

                        Hero.CleanUp();
                        GameMenu.CleanUp();

                        //#if BACK_BUFFER_FULL || BACK_BUFFER_LEVEL
                            GameWorld.clearBackBuffer();
                        //#endif

                        //#if TILESTYPE_SEPARATE
                            nCurrentGameState = GAME_STATE_LOADING;
                            GameMenu.Init(this);
                            doRepaint();
                        //#endif
                  
                        //#if IMGGROUP_12x12xLimited
                            Resources.cleanMenuResources();
                            Resources.initGameResources();
                        //#endif

                        //#if !TILESTYPE_SEPARATE
                            nCurrentGameState = GAME_STATE_LOADING;
                            GameMenu.Init(this);
                        //#endif
                        doRepaint();

                        if (loadLevel(Hero.m_nLevel)) {
                            bCurrentTick = 0;
                            nCurrentGameState = GAME_STATE_GET_READY;
                            GameMenu.CleanUp();
                            //#if SOUND_MMAPI || SOUND_NOKIA_RT || SAMSUNG_MMF || SHARP_MMF
                                soundPlay(Constants.SOUND_NEW_LIFE);
                            //#endif

                            //#if USE_GAME_TIPS
                                GameWorld.gameTips[Constants.TIP_LEVEL]             = 0;
                                GameWorld.gameTips[Constants.TIP_SPRING]            = 3;
                                GameWorld.gameTips[Constants.TIP_FIREWALL]          = 2;
                                GameWorld.gameTips[Constants.TIP_DYNAMITE]          = 12;
                                GameWorld.gameTips[Constants.TIP_PICKAXE]           = 5;
                                GameWorld.gameTips[Constants.TIP_CRASHING_PLATFORM] = 10;
                                GameWorld.gameTips[Constants.TIP_TELEPORT]          = 13;
                            //#endif
                        }
                        break;
                    }

                    case StringsID.nStrID_Resume: {
                        GameMenu.CleanUp();
                        nCurrentGameState = GAME_STATE_START;
                        //#if !FULL_CANVAS
                            removeAllCmds();
                            addCmd(StringsID.nStrID_Pause, -1);
                        //#endif
                        break;
                    }

                    case StringsID.nStrID_QuitGame:
                        endOfGame = true;
                    case StringsID.nStrID_QuitLevel: {
                        GameWorld.CleanUp();
                        GameMenu.CleanUp();

                        //#if IMGGROUP_12x12xLimited
                            Resources.cleanGameResources();
                            Resources.initMenuResources();
                        //#endif

                        if (Hero.m_nTotalScores > 0) {
                            nCurrentGameState = GAME_STATE_UPLOAD_SCORE;
                            //#if !SCORE_SAVE_RMS
                                GameMenu.Init(this);
                            //#endif
                        }
                        else {
                            if (endOfGame) {
                                nCurrentGameState = GAME_STATE_EXIT;
                            }
                            else {
                                nCurrentGameState = GAME_STATE_MENU;
                                GameMenu.Init(this);
                            }
                        }
                        break;
                    }

                    case StringsID.nStrID_Quit: {
                        nCurrentGameState = GAME_STATE_EXIT;
                        break;
                    }
                }
                break;
            }
        }
    }

    /**
     *
     */
    public void DoKey() {
        if (keyWasPressed(keyUP | keyNUM2) || keyIsHeld(keyUP | keyNUM2)) {
            Hero.ForceMoveUp();
        }
        else if (keyWasPressed(keyNUM8 | keyDOWN) || keyIsHeld(keyNUM8 | keyDOWN)) {
            Hero.ForceMoveDown();
        }
        else if (keyWasPressed(keyNUM1) || keyIsHeld(keyNUM1)) {
            Hero.ForceMoveJump(true, false);
        }
        else if (keyWasPressed(keyNUM3) || keyIsHeld(keyNUM3)) {
            Hero.ForceMoveJump(false, true);
        }
        else if (keyWasPressed(keyNUM4 | keyLEFT) || keyIsHeld(keyNUM4 | keyLEFT)) {
            Hero.ForceMoveLeft();
        }
        else if (keyWasPressed(keyNUM6 | keyRIGHT) || keyIsHeld(keyNUM6 | keyRIGHT)) {
            Hero.ForceMoveRight();
        }
        else if (keyWasPressed(keyFIRE | keyNUM5)) {
            Hero.ForceFire();
        }
        else {
            Hero.ForceStop();
        }
    }

    /**
     *
     */
    public void keyPressed(int keyCode) {
        //#if Nokia && E61
            this.keyCode = keyCode;
        //#endif
        keysPressed = getKeyState(keyCode);
        keysHold |= keysPressed;
    }

    public void keyReleased(int keyCode) {
        keysReleased = getKeyState(keyCode);
        keysHold &= ~keysReleased;
    }

    public static int getKeyState(int keyCode) {
        int key_state = 0;

        switch (keyCode) {
            case pdKeyUP:
                key_state = keyUP;
            break;

            case pdKeyDOWN:
                key_state = keyDOWN;
            break;

            case pdKeyRIGHT:
                key_state = keyRIGHT;
            break;

            case pdKeyLEFT:
                key_state = keyLEFT;
            break;

            case pdKeyFIRE:
                key_state = keyFIRE;
            break;

            //#if Nokia && E61
            case pdKeyM:
            //#endif
            case pdKey0:
                key_state = keyNUM0;
            break;

            //#if Nokia && E61
            case pdKeyR:
            //#endif
            case pdKey1:
                key_state = keyNUM1;
            break;

            //#if Nokia && E61
            case pdKeyT:
            //#endif
            case pdKey2:
                key_state = keyNUM2;
            break;

            //#if Nokia && E61
            case pdKeyY:
            //#endif
            case pdKey3:
                key_state = keyNUM3;
            break;

            //#if Nokia && E61
            case pdKeyF:
            //#endif
            case pdKey4:
                key_state = keyNUM4;
            break;

            //#if Nokia && E61
            case pdKeyG:
            //#endif
            case pdKey5:
                key_state = keyNUM5;
            break;

            //#if Nokia && E61
            case pdKeyH:
            //#endif
            case pdKey6:
                key_state = keyNUM6;
            break;

            //#if Nokia && E61
            case pdKeyV:
            //#endif
            case pdKey7:
                key_state = keyNUM7;
            break;

            //#if Nokia && E61
            case pdKeyB:
            //#endif
            case pdKey8:
                key_state = keyNUM8;
            break;

            //#if Nokia && E61
            case pdKeyN:
            //#endif
            case pdKey9:
                key_state = keyNUM9;
            break;

            //#if Nokia && E61
            case pdKeyU:
            //#endif
            case pdKeySTAR:
                key_state = keySTAR;
            break;

            //#if Nokia && E61
            case pdKeyJ:
            //#endif
            case pdKeyPOUND:
                key_state = keyPOUND;
            break;

            case pdKeyLEFTSOFT:
                key_state = keyLEFTSOFT;
            break;

            case pdKeyRIGHTSOFT:
                key_state = keyRIGHTSOFT;
        }
        key_state |= keyANY;
        return key_state;
    }

    public static boolean keyIsHeld(int key) {
        return ((keysHold & key) != 0);
    }

    public static boolean keyWasPressed(int key) {
        return ((keysPressed & key) != 0);
    }

    public static void resetKey(int key) {
        keysPressed &= ~key;
    }

    public static void resetKeys() {
        keysPressed       = 0;
        keysHold          = 0;
        keysReleased      = 0;
    }


    /**
     *
     */
    //#if SOUND_NOKIA_RT
        public void soundStateChanged(Sound sound, int event) {
            if (event != Sound.SOUND_PLAYING && soundState != SS_PAUSED) {
                soundState = SS_STOPED;
                soundId = -1;
            }
        }

        public void soundLoad(byte id, byte[] data) {
            if (id >= 0 && id < sounds.length) {
                try {
                    sounds[id] = new Sound(data, Sound.FORMAT_TONE);
                    sounds[id].setSoundListener(this);
                }
                catch (Exception ex) {
                    //ex.printStackTrace();
                }
            }
        }

        public void soundUnload() {
            for (int i = 0; i < sounds.length; i++) {
                if(sounds[i] != null) {
                    sounds[i].release();
                    sounds[i] = null;
                }
            }
            System.gc();
        }

        public static void soundPlay(byte id) {
            if (GameMenu.isSoundOn()) {
                if (soundState == SS_PLAYING) {
                    soundStop(soundId);
                }
                soundState = SS_PLAYING;
                soundId = id;
                try{
                    sounds[id].play(1);
                }
                catch (Throwable throwable) {
                    //throwable.printStackTrace();
                }
            }
        }

        public static void soundStop(byte id) {
            try {
                soundState = SS_STOPED;
                sounds[id].stop();
                soundId = -1;
            }
            catch (Throwable throwable) {
            }
        }

    //#elif SOUND_MMAPI
        public void playerUpdate(Player player, String event, Object eventData) {
            if (event == PlayerListener.END_OF_MEDIA) {
                //#if SOUND_MMAPI_TYPE1
                    try {
                        soundPlayer[soundId].deallocate();
                    }
                    catch(Exception ex) {}
                //#endif
                byte tmp = soundId;
                soundId = -1;
                //#if USE_SOUND_VOLUME_CONTROL
                    if (GameMenu.iMenuScreenID == GameMenu.MENU_SCR_VOLUME_CONTROL) {
                        soundPlay(tmp);
                    }
                //#endif
            }
        }

        public static byte getPlayerState(byte id) {
            if (-1 < id && id < soundPlayer.length) {
                try {
                    if (soundPlayer[id] == null) return SS_NOT_LOADED;
                    switch (soundPlayer[id].getState()) {
                        case Player.PREFETCHED:
                            return SS_PREFETCHED;
                        case Player.STARTED:
                            return SS_STARTED;
                        case Player.CLOSED:
                            return SS_CLOSED;
                        case Player.REALIZED:
                            return SS_REALIZED;
                        case Player.UNREALIZED:
                            return SS_UNREALIZED;
                    }
                }
                catch (Exception ex) {
                    //ex.printStackTrace();
                }
            }
            return SS_NOT_LOADED;
        }

        public void soundLoad(byte id) {
            if (id >= 0 && id < soundPlayer.length) {
                DataInputStream in = null;
                try {
                    switch (id) {
                        case SOUND_BONUS:
                            in = new DataInputStream(MTMMidlet.the_class.getResourceAsStream("res/bonus.mid"));
                        break;
                        case SOUND_DIE:
                            in = new DataInputStream(MTMMidlet.the_class.getResourceAsStream("res/die.mid"));
                        break;
                        case SOUND_KILL:
                            in = new DataInputStream(MTMMidlet.the_class.getResourceAsStream("res/kill.mid"));
                        break;
                        case SOUND_LVL_CLEAR:
                            in = new DataInputStream(MTMMidlet.the_class.getResourceAsStream("res/lvl_clear.mid"));
                        break;
                        case SOUND_NEW_LIFE:
                            in = new DataInputStream(MTMMidlet.the_class.getResourceAsStream("res/new_life.mid"));
                        break;
                        case SOUND_THEME:
                            in = new DataInputStream(MTMMidlet.the_class.getResourceAsStream("res/theme.mid"));
                        break;
                        case SOUND_TIMEWARNING:
                            in = new DataInputStream(MTMMidlet.the_class.getResourceAsStream("res/timewarning.mid"));
                        break;
                    }
                    soundPlayer[id] = Manager.createPlayer(in, "audio/midi");
                    soundPlayer[id].realize();
                    //#if USE_SOUND_VOLUME_CONTROL
                        volumeControl[id] = (VolumeControl) soundPlayer[id].getControl("VolumeControl");
                    //#endif
                    //#if SOUND_MMAPI_TYPE2
                        soundPlayer[id].prefetch();
                    //#endif
                    soundPlayer[id].addPlayerListener(this);
                }
                catch (Exception ex) {
                    //ex.printStackTrace();
                }
                finally {
                    try {
                        in.close();
                    }
                    catch(Exception ex1) {}
                    in = null;
                    System.gc();
                }
            }
        }

        public void soundUnload() {
            for (int i = 0; i < soundPlayer.length; i++) {
                if (soundPlayer[i] != null) {
                    soundPlayer[i].close();
                    soundPlayer[i] = null;
                    //#if USE_SOUND_VOLUME_CONTROL
                        volumeControl[i] = null;
                    //#endif
                }
            }
            System.gc();
            soundId = -1;
        }

        public static void soundPlay(byte id) {
            if (GameMenu.isSoundOn()) {
                if (id != soundId) {
                    soundStop(soundId);
                    try { 
                        //#if SOUND_MMAPI_TYPE1
                            if (getPlayerState(id) == SS_PREFETCHED) {
                                soundPlayer[id].deallocate();
                            }
                            soundPlayer[id].prefetch();
                        //#endif
                        soundPlayer[id].start();
                    }
                    catch (Exception ex) {}
                    soundId = id;
                }
            }
        }

        public static void soundStop(byte id) {
            if (getPlayerState(id) == SS_STARTED) {
                try {
                    soundPlayer[id].setMediaTime(Long.MAX_VALUE);
                    soundPlayer[id].stop();
                    soundId = -1;
                }
                catch (Exception ex) {}
                //#if SOUND_MMAPI_TYPE1
                    try {
                        soundPlayer[id].deallocate();
                    }
                    catch (Exception ex) {}
                //#endif
            }
        }

    //#elif SAMSUNG_MMF
    //#elif SHARP_MMF
    //#endif

    /**
     *
     */

    //#if !FULL_CANVAS
        public Command cmdLeft  = null;
        public Command cmdRight = null;
        public Command cmdBack  = null;
        public int leftSoftButtonId = -1, rightSoftButtonId = -1;
        
        public void commandAction(Command cmd, Displayable d) {
            if (cmd == cmdLeft) {
                keyPressed(pdKeyLEFTSOFT);
            }
            if (cmd == cmdRight || cmd == cmdBack) {
                keyPressed(pdKeyRIGHTSOFT);
            }
        }

        public void addCmd(int leftSoftButtonId, int rightSoftButtonId) {
            if (this.leftSoftButtonId != leftSoftButtonId && leftSoftButtonId > -1 && leftSoftButtonId < Resources.mStrings.length) {
                this.leftSoftButtonId = leftSoftButtonId;
                cmdLeft = new Command(Resources.mStrings[leftSoftButtonId], Command.OK, 0);
                addCommand(cmdLeft);
            }
            if (this.rightSoftButtonId != rightSoftButtonId && rightSoftButtonId > -1 && rightSoftButtonId < Resources.mStrings.length) {
                this.rightSoftButtonId = rightSoftButtonId;
                cmdBack = new Command(Resources.mStrings[rightSoftButtonId], Command.BACK, 1);
                addCommand(cmdBack);
                //#if SE && T610
                    cmdRight = new Command(Resources.mStrings[rightSoftButtonId], Command.CANCEL, 1);
                    addCommand(cmdRight);
                //#endif
            }
        }

        public void removeAllCmds() {
            leftSoftButtonId = -1;
            rightSoftButtonId = -1;
            if (cmdLeft != null) {  
                removeCommand(cmdLeft);
                cmdLeft = null;
            }
            if (cmdRight != null) {  
                removeCommand(cmdRight);
                cmdRight = null;
            }
            if (cmdBack != null) {  
                removeCommand(cmdBack);
                cmdBack = null;
            }
        }
    //#endif

    /**
     *
     */
    private void logoWait(long startTime, int delay) {
        long time = System.currentTimeMillis() - startTime;
        if (time < delay) {
            try {
                mainThread.sleep(delay - time);
            }
            catch(Exception tex){}
        }
    }
}
